#include "tknetbusi.h"
#include "tkconstants.h"
#include "tkerror.h"
#include "tklog.h"

#include "clientinfo.dsc.h"
#include "memberlist.dsc.h"
#include "message.dsc.h"
#include "tknetbusi.h"

/* fixme: handler should use tk_connect not custom_socket */

/**
#define MSG_TYPE_MEMBER_LIST    0
#define MSG_TYPE_CLIENT_INFO    1
#define MSG_TYPE_COMM_MSG       2
#define MSG_TYPE_LOGOUT         3
**/

int hd_send_client_information(struct select_env *env, struct custom_socket *s, int event_type);
int hd_get_clients_list_information(struct select_env *env, struct custom_socket *s, int event_type);
int hd_communicating(struct select_env *env, struct custom_socket *s, int event_type);

int do_after_connect_entry(struct select_env *env, struct custom_socket *s)
{
        int r = 0;
        struct tk_connect *conn = NULL;

        conn = get_tk_connect(s);
        conn->stage = TK_CONNECT_SYNC_CLIENT_INFO;	/* send clinet info to server */

        /* add read event */
        r = select_add_write_event(env, s->event);
        if (r) {
                elog("add write event failed");
                tk_connection_error(env, conn);

                return -1;
        }

        /* set write handler */
        s->handler = hd_send_client_information;

	return 0;
}

/* first application handler */
int hd_send_client_information(struct select_env *env, struct custom_socket *s, int event_type)
{
	struct tk_connect *conn = (struct tk_connect*)s->ptr;
	struct tk_message *msg = &conn->recv_msg;
	void *event = s->event;
	struct tk_message tmp_msg;
	clientinfo client;
	memberlist *memlist;
	struct member *mem;
	int len;
	int r, rc;
	
        if (event_type != EVENT_WRITE) {
                elog("hd_send_client_information raised by write event");
		conn->failed = 1;

                return TK_ERROR;
        }

	r = tk_do_send_msg(conn);
	if (r == TK_SEND_BODY_DONE) {
		/* del write handler and add read handler */
		(VOID)select_del_write_event_event(env, (void*)s->event);
		(VOID)select_add_read_event(env, (void*)s->event);

		/* receive clients list information */
		s->handler = hd_recv_clients_list_information;
		conn->stage = TK_CONNECT_SYNC_CLIENT_INFO_DONE;
	}
	else if (r == TK_ERROR) {
		elog("tk_do_send_msg failed");
		conn->failed = 1;
		return TK_ERROR;
	}	
	else if (r == TK_NO_MORE_SEND_MSG) {
		elog("tk_do_send_msg no more send message");
		conn->failed = 1;
		return TK_ERROR;
	}
	else {	/* EAGAIN */
		return TK_EAGAIN;
	}

        return TK_OK;
}

int hd_recv_clients_list_information(struct select_env *env, struct custom_socket *s, int event_type)
{
	int r;
	struct tk_connect *conn = (struct tk_connect*)s->ptr;
	struct tk_message *msg;
	struct member *mem;
	memberlist mem_list;
	char *buffer;
	int buffer_len;
	void *event = s->event;
	clientinfo client;

	conn->stage = TK_CONNECT_SYNC_CLIENTS_LIST;	/* receive client information */

        if (event_type & EVENT_LOCAL_ERROR) {
                conn->failed = 1;
                return TK_OK;
        }
        else if (event_type & EVENT_REMOTE_CLOSE) {
                conn->finished = 1;
                return TK_OK;
        }

	if (event_type != EVENT_READ) {
                elog("hd_recv_clients_list_information raised by read event");
                return TK_ERROR;
	}

	/* recv initialize clients information */
	/*
        2. TK_AGAIN (internal buffer is empty)
        3. TK_ERROR
        4. TK_DONE      (remote close)
        5. TK_RECV_BODY_DONE should delete event(if non-blocking mode)
	*/

	r = tk_do_recv_msg(conn);
	if (r == TK_RECV_BODY_DONE) {
		/* add read event, del write event*/
		(VOID)select_add_read_event(env, (void*)s->event);
		/* must del event or select will raise write event all time, write event will be added by add message if needed */
		(VOID)select_del_write_event(env, (void*)s->event);
		/* change handler */
		s->handler = hd_communicating;

		/* deserial memberlist */
		msg = get_recv_message(conn);
		tk_message_buffer(msg, buffer, buffer_len);
		r = DSCDESERIALIZE_JSON_memberlist("GBK", buffer, &buffer_len, &mem_list);	
		if (r) {
			elog("DSCDESERIALIZE_JSON_memberlist failed");
			conn->failed = 1;

			return TK_ERROR;
		}
		
	/* show client list */
		/* TODO */
		/* 	int     clientid ;
			char    clientname[ 40 + 1 ] ;
			char    ip[ 40 + 1 ] ;
		*/
		elog("Show clients list...");
		int i;
		for (i = 0; i < mem_list._nodes_count; i++) {
			mem = &mem_list.nodes[i];
			elog("clientid[%d] - clientname[%s] - ip[%s]", mem->clientid, mem->clientname, mem->ip);
		}
		elog("Show clients list end");

		conn->stage = TK_CONNECT_SYNC_CLIENTS_LIST_DONE;	/* sync client list ok */
	}
	else if (r == TK_DONE) {
		elog("remote close socket");
		conn->finished = 1;
	
		return TK_OK;
	}
	else if (r == TK_OK) {
		elog("not possible tk_ok");
		conn->failed = 1;
		
		return TK_ERROR;
	}
	else if (r == TK_ERROR) {
		conn->failed = 1;
		
		return TK_ERROR;
	}
	else {
		return TK_AGAIN;
	}

	return TK_OK;
}

/* catch read and write event */
int hd_communicating(struct select_env *env, struct custom_socket *s, int event_type)
{
	int r = 0, deserial_flag;
	int len;
	struct tk_connect *conn = (struct tk_connect*)s->ptr;
	void *event = s->event;
	message msg;
	struct tk_message *recv_msg;
	struct tk_message *send_msg;
	int msg_type;
	int body_len;
	char *buffer;
	int buffer_len;

	clientinfo cinfo;
	memberlist mlist;
	message msg;

	member *mem = NULL;

	conn->stage = TK_CONNECT_COMMUNICATING;		/* commucating with server */

	if (event_type & EVENT_LOCAL_ERROR) {
		conn->failed = 1;
		return TK_ERROR;
	}
	else if (event_type & EVENT_REMOTE_CLOSE) {
		conn->finished = 1;
		return TK_OK;
	}

	if (event_type & EVENT_READ) {

		do {
	/* 
	2. TK_AGAIN (internal buffer is empty)
        3. TK_ERROR
        4. TK_DONE      (remote close)
        5. TK_RECV_BODY_DONE should delete event(if non-blocking mode)
	*/
			r = tk_do_recv_msg(conn);
			if (r == TK_RECV_BODY_DONE) {
				recv_msg = get_recv_message(conn);
				msg_type = tk_message_type(recv_msg);
				tk_message_buffer(recv_msg, buffer, buffer_len);

				switch(msg_type) {
					case MSG_TYPE_MEMBER_LIST:
					{
						r = DSCDESERIALIZE_JSON_memberlist("GBK", buffer, &buffer_len, &mlist);
						if (!r) {
							elog("Show clients list...");
							int i;
							for (i = 0; i < mlist._nodes_count; i++) {
								mem = &mlist.nodes[i];
								elog("clientid[%d] - clientname[%s] - ip[%s]", mem->clientid, mem->clientname, mem->ip);
							}
							elog("Show clients list end");
						}
						break;
					}
					case MSG_TYPE_COMM_MSG:
					{
						r = DSCDESERIALIZE_JSON_message("GBK", buffer, buffer_len, &msg);
						if (!r) {
							elog("RECV MESSAGE: [%d] - [%s] - [%d] - [%s]", msg.clientid, 
														msg.clientname, 
														msg.contentlen, 
														msg.content);
						}
						break;
					}
					default:
					{
						elog("unknow type message");
						break;
					}
				}
				if (r) {
					elog("deseriaize json failed, discard recived message!");	
				}
			}
			else if (r == TK_ERROR) {
				conn->failed = 1;
				elog("communicating read failed");
				return TK_ERROR;
			}
			else if (r == TK_DONE) {
				elog("hd_get_client_information remote close");
				conn->finished = 1;
			}

		} while (r == TK_RECV_BODY_DONE);	
	}
	if (event_type & EVENT_WRITE) {
	/**
        1. TK_AGAIN (internal buffer is full)
        2. TK_ERROR(errno)
        5. TK_NO_MORE_SEND_MSG (attention: other success status) should delete event(if non-blocking mode)
        6. TK_SEND_BODY_DONE: should delete event(if non-blocking mode)
	**/
		do {
			r = tk_do_send_msg(conn);
			if (r == TK_ERROR) {
				conn->failed = 1;
				elog("communicating write failed");
				return TK_ERROR;	
			}
			else if (r == TK_NO_MORE_SEND_MSG) {
				select_del_write_event(env, event);
			}

		} while (r == TK_SEND_BODY_DONE);
	}
	
	return TK_OK;
}

int hd_test_connect(struct select_env *env, struct custom_socket *s, int event_type)
{
	int r;
	struct tk_connect *conn = (struct tk_connect*)s->ptr;

	r = tk_connect_test(s->sockfd);
	if (r) {
		elog("connect failed");
		conn->failed = 1;

		return TK_ERROR;
	}

	return TK_OK;
}

int hd_handler_entry(struct select_env *env, struct custom_socket *s, int event_type)
{
	struct tk_connect *conn = (struct tk_connect*)s->ptr;

	if (event_type & EVENT_LOCAL_ERROR) {
		conn->failed = 1;
	}
	else if (event_type & EVENT_REMOTE_CLOSE) {
		conn->finished = 1;
	}	

	if (conn->finished) {
		return TK_OK;
	}
	else if (conn->failed) {
		return TK_ERROR;	
	}

	return s->handler(env, s, event_type);		
}
